<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>https://codepen.io/pnpicot/pen/PoXpYWp</title>
    <style>
		@import url('https://fonts.googleapis.com/css2?family=Cairo:wght@200;300;400;500;600;700;800;900;1000&family=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500;1,700;1,900&display=swap');
		:root {
			--primary: #00121B;
			--secondary: #80FF80;
			--complementary: #7FFFD4;
			--accent: #eb3461;
			--dark: #000;
			--font: 'Cairo', sans-serif;
			--font-scale: 0.390625vw;
			--button-width: 4rem;
			--row-height: 2rem;
		}


		@function getFont($unit) {
			@return calc(#{$font-scale} + #{$unit});
		}

		@mixin r-flex {
			position: relative;
			display: flex;
		}

		@mixin a-flex {
			position: absolute;
			display: flex;
		}

		body {
			@include r-flex;

			justify-content: center;
			align-items: center;
			height: 100%;
			min-height: 100vh;
			margin: 0;
			padding: 0;
			background: linear-gradient(var(--primary), darken(var(--primary), 5%));
			overflow: hidden;
			font-family: $font;
		}

		.d-flex { display: flex; }
		.row { flex-direction: row; }
		.flex-fill { flex: 1 1 auto; width: 100%; }
		.justify-content-center { justify-content: center; }
		.justify-content-start { justify-content: flex-start; }
		.justify-content-end { justify-content: flex-end; }
		.align-items-center { align-items: center; }
		.align-items-start { align-items: flex-start; }
		.align-items-end { align-items: flex-end; }

		@property --angle {
			syntax: "<angle>";
			inherits: false;
			initial-value: 0turn;
		}

		@keyframes conic-rotate {
			to {
				--angle: 1turn;
			}
		}

		.table-container {
			@include r-flex;

			width: 85vw;
			height: calc(((var(--data-limit) + 1) * 2rem) + 10rem);
			transform-style: preserve-3d;
			box-shadow: inset 0 -.5rem 1rem rgba(var(--primary), .5), inset 0 0 1rem rgba(var(--complementary), .3);
			border: 2px solid rgba(var(--complementary), .5);
			border-radius: 1rem;
			flex-direction: column;

			&::before {
				@include a-flex;

				content: '';
				width: 100%;
				height: 100%;
				top: 0;
				left: 0;
				background: conic-gradient(from var(--angle), var(--secondary), rgba(var(--complementary), .5), var(--secondary), royalblue, var(--secondary));
				filter: blur(.5rem);
				transform: translatez(-2px);
				z-index: -2;
				opacity: 0.99;
				animation: conic-rotate 12s infinite linear;
			}

			&::after {
				@include a-flex;

				content: '';
				width: 100%;
				height: 100%;
				top: 0;
				left: 0;
				background-color: rgba(var(--primary), .95);
				transform: translatez(-1px);
				z-index: -1;
				border-radius: inherit;
			}
		}

		.table {
			@include r-flex;

			width: 100%;
			padding: 1rem 0 0 0;
			flex-direction: column;
			align-items: center;
			justify-content: center;
			background-image: linear-gradient(90deg, transparent, rgba(var(--secondary), .15), transparent);
			-webkit-background-image: linear-gradient(90deg, transparent, rgba(var(--secondary), .15), transparent);
			overflow: hidden;
			box-shadow: 0 .5rem 1rem rgba(var(--dark), .1);

			.table-row {
				@include r-flex;

				flex-direction: row;
				gap: inherit;
				width: calc(100% - 4rem);
				padding: 0 2rem;
				transition: opacity .5s;
			}

			.table-row:nth-child(2n) {
				background-color: rgba(var(--dark), .1);
			}

			.table-col {
				@include r-flex;

				flex-direction: column;
				gap: inherit;
				flex: 1 1 0;
				height: var(--row-height);
				justify-content: center;
				align-items: flex-start;
				color: var(--complementary);
				text-shadow: 0 0 .5rem rgba(var(--complementary), .6);
				font-size: getFont(12px);
				padding: 0 1rem;
				cursor: pointer;
				white-space: nowrap;

				span {
					@include r-flex;

					cursor: pointer;

					&::before, &::after {
						@include a-flex;

						content: '';
						height: 70%;
						width: .3rem;
						border-top: 2px solid var(--complementary);
						border-bottom: 2px solid var(--complementary);
						opacity: 0;
						pointer-events: none;
						transition: opacity .3s, transform .3s;
					}

					&::before {
						border-left: 2px solid var(--complementary);
						left: 0;
						top: 50%;
						transform: translate(-.5rem, -50%) scale(0.6) rotate(20deg);
					}

					&::after {
						border-right: 2px solid var(--complementary);
						right: 0;
						top: 50%;
						transform: translate(.5rem, -50%) scale(0.6) rotate(20deg);
					}

					&:hover::before {
						opacity: 1;
						transform: translate(-1rem, -50%) scale(0.8) rotate(0deg);
					}

					&:hover::after {
						opacity: 1;
						transform: translate(1rem, -50%) scale(0.8) rotate(0deg);
					}
				}
			}

			.table-heading .table-col {
				color: var(--secondary) !important;
				text-shadow: 0 0 .5rem rgba(var(--secondary), .6);
				font-weight: 600;
				text-transform: uppercase;
			}
		}

		.pagination-container {
			@include r-flex;

			flex: 1 1 auto;
			width: 100%;
			justify-content: flex-end;
			align-items: center;
			padding-bottom: 1.5rem;
			padding-top: 1rem;
			flex-direction: column;
		}

		.pagination-wrapper {
			@include r-flex;

			height: fit-content;
			overflow: hidden;
			justify-content: flex-start;
			width: var(--button-width) * 5;
		}

		.pagination {
			@include r-flex;

			flex-direction: row;
			list-style-type: none;
			margin: 0;
			padding: 0;
			align-items: center;
			justify-content: flex-start;
			transition: transform .5s;

			& > li {
				@include r-flex;

				width: var(--button-width);
				max-width: var(--button-width);
				flex: 0 0 auto;
				height: 3rem;
				justify-content: center;
				align-items: center;
				color: var(--secondary);
				font-size: getFont(18px);
				z-index: 5;
				cursor: pointer;
				user-select: none;
				text-shadow: 0 0 .4rem rgba(var(--secondary), .6);

				span {
					pointer-events: none;
				}

				&.active span {
					@include r-flex;

					height: 2.5rem;
					padding: 0 1rem;
					font-weight: bolder;
					align-items: center;
					justify-content: center;
					background-image: linear-gradient(45deg, rgba(var(--secondary), .1), rgba(var(--primary), .4));
					border: 1px solid rgba(var(--secondary), .3);
					color: lighten(var(--complementary), 10%);
					border-radius: 5px;
					text-shadow: 0 0 .4rem rgba(lighten(var(--complementary), 10%), .6);
				}
			}
		}

		.pagination-info {
			@include a-flex;

			font-size: getFont(10px);
			color: desaturate(var(--secondary), 70%);
			bottom: 4.5rem;
			text-shadow: 0 0 .5rem rgba(desaturate(var(--secondary), 70%), .5);
		}

		.pagination-extreme {
			@include r-flex;

			height: 3rem;
			width: 10rem;
			border: none;
			background-color: transparent;
			border-radius: 5px;
			justify-content: center;
			align-items: center;
			color: var(--secondary);
			font-size: getFont(15px);
			cursor: pointer;
			transition: transform .3s;

			&:hover {
				transform: scale(1.4);
			}
		}

		.progress-bar {
			@include r-flex;

			width: calc(100% - 6rem);
			height: 2px;
			background-color: rgba(var(--complementary), .1);
			border-radius: 2px;
			margin: 0 3rem 2rem  3rem;

			.progress-point {
				@include a-flex;

				height: .5rem;
				width: .5rem;
				background-color: darken(var(--complementary), 60%);
				border-radius: 50%;
				top: 50%;
				left: 0;
				transform: translateY(-50%);
				transition: left .5s;
			}
		}

		.infos {
			@include a-flex;

			top: 0;
			left: 50%;
			transform: translateX(-50%);
			font-family: $font;
			margin: 0;
			padding: 0;
			width: 100%;
			justify-content: center;
			align-items: center;
			height: 6rem;
			font-size: getFont(12px);
			line-height: 24px;
			font-weight: 600;
			background-color: var(--secondary);
			background-image: linear-gradient(45deg, royalblue, var(--secondary), var(--complementary));
			-webkit-background-image: linear-gradient(45deg, var(--secondary), royalblue, var(--complementary));
			background-clip: text;
			-webkit-background-clip: text;
			color: transparent;
			text-shadow: 0 0 .4rem rgba(var(--complementary), .4);
		}
    </style>
</head>
<body>
<p class="infos">
	You can switch pages using your mouse wheel !<br />
	The amount of rows per pages depends on the height of your window when loading the page.
</p>

<div class="table-container" style="--data-limit: 9">
	<div class="table" id="table-0" data-limit="9">
		<div class="table-row table-heading">
			<div class="table-col">
				#
			</div>
			<div class="table-col">
				First name
			</div>
			<div class="table-col">
				Last name
			</div>
			<div class="table-col">
				Title
			</div>
			<div class="table-col">
				Completed
			</div>
		</div>
		<div class="table-row" data-copy="103">
			<div class="table-col">
				<span class="auto-increment">0</span>
			</div>
			<div class="table-col">
				<span class="auto-firstname"></span>
			</div>
			<div class="table-col">
				<span class="auto-lastname"></span>
			</div>
			<div class="table-col">
				<span class="auto-title"></span>
			</div>
			<div class="table-col">
				<span class="auto-integer" min="0" max="250"></span>
			</div>
		</div>
	</div>

	<div class="pagination-container">
		<div class="d-flex row flex-fill align-items-end justify-content-center">
			<span class="pagination-info"></span>
			<button class="pagination-extreme pagination-left">
				<i class="fa-solid fa-angles-left"></i>
			</button>
			<button class="pagination-extreme pagination-left-one">
				<i class="fa-solid fa-angle-left"></i>
			</button>
			<div class="d-flex flex-fill justify-content-center">
				<div class="pagination-wrapper">
					<ul class="pagination" data-table="table-0"></ul>
				</div>
			</div>
			<button class="pagination-extreme pagination-right-one">
				<i class="fa-solid fa-angle-right"></i>
			</button>
			<button class="pagination-extreme pagination-right">
				<i class="fa-solid fa-angles-right"></i>
			</button>
		</div>
	</div>

	<div class="progress-bar">
		<div class="progress-point"></div>
	</div>
</div>

<script>
	const FIRSTNAMES = [
		'John', 'Steve', 'Marc', 'Franklin', 'Isaac', 'Vincent', 'Edwin',
		'Ashlyn', 'Anthony', 'Alia', 'Abby', 'Francesca'
	];

	const LASTNAMES = [
		'Shafer', 'Whitetaker', 'Glenn', 'Stephens', 'Sherman', 'Howard',
		'Kent', 'Clay', 'Beck', 'Simmons', 'Briggs', 'Lee', 'Maxwell'
	];

	const TITLES = [
		'CEO', 'President', 'Vice President', 'Director', 'Manager',
		'Developer'
	];

	const BTN_WIDTH = 4;

	document.addEventListener('DOMContentLoaded', () => {
		initCopies();
		initAutoLimits();
		initAutoIncrements();
		initAutoFirstnames();
		initAutoLastnames();
		initAutoTitles();
		initAutoIntegers();
		initPaginations();
	});

	function initCopies()
	{
		let targets = [...document.querySelectorAll('*[data-copy]')];

		targets.reverse().forEach((original) => {
			let amount = parseInt(original.getAttribute('data-copy'));

			for (let i = 0; i < amount; i++) {
				let copy = original.cloneNode(true);

				original.parentNode.insertBefore(copy, original.nextSibling);
			}
		});
	}

	function initAutoIncrements()
	{
		let autos = document.querySelectorAll('.auto-increment');

		autos.forEach((auto, i) => {
			auto.innerHTML = i + 1;
		});
	}

	const rand = (a, b) => Math.floor((Math.random() * b) + a);

	function initAutoFirstnames()
	{
		let autos = document.querySelectorAll('.auto-firstname');

		autos.forEach((auto) => {
			auto.innerHTML = FIRSTNAMES[rand(0, FIRSTNAMES.length)];
		});
	}

	function initAutoLastnames()
	{
		let autos = document.querySelectorAll('.auto-lastname');

		autos.forEach((auto) => {
			auto.innerHTML = LASTNAMES[rand(0, LASTNAMES.length)];
		});
	}

	function initAutoTitles()
	{
		let autos = document.querySelectorAll('.auto-title');

		autos.forEach((auto) => {
			auto.innerHTML = TITLES[rand(0, TITLES.length)];
		});
	}

	function initAutoIntegers()
	{
		let autos = document.querySelectorAll('.auto-integer');

		autos.forEach((auto) => {
			let min = parseInt(auto.getAttribute('min'));
			let max = parseInt(auto.getAttribute('max'));

			auto.innerHTML = rand(min, max);
		});
	}

	function initPaginations()
	{
		let paginations = document.querySelectorAll('.pagination');

		paginations.forEach((pagination) => {
			let table = document.getElementById(pagination.getAttribute('data-table'));

			pagination.setAttribute('data-x', '0');

			if (table !== null && table !== undefined) {
				createPagination(pagination, table);

				pagination.closest('.table-container').addEventListener('wheel', (event) => {
					event.preventDefault();

					scrollPages(
							event.wheelDelta
									? event.wheelDelta > 0
									: event.deltaY < 0, pagination,
							table
					);
				});
			}
		});
	}

	function createPagination(pagination, table)
	{
		let limit = parseInt(table.getAttribute("data-limit"));
		let rows = table.querySelectorAll('.table-row:not(.table-heading)');
		let page_count = Math.ceil(rows.length / limit);

		if (isNaN(limit))
			limit = 10;

		rows.forEach((row, index) => {
			if (index >= limit)
				row.style.display = 'none';
		});

		for (let i = 0; i < page_count; i++) {
			let new_button = document.createElement('li');

			new_button.innerHTML = "<span>" + (i + 1) + "</span>";

			if (i === 0)
				new_button.classList.add('active');

			pagination.appendChild(new_button);

			new_button.addEventListener('click', () => {
				switchPage(pagination, table, i);
			});
		}

		updatePaginationInfos(pagination, table, page_count, 0);
		initPaginationExtremes(pagination, table, page_count);
	}

	function scrollPages(direction, pagination, table)
	{
		let last_active = pagination.querySelector('li.active');
		let buttons = pagination.querySelectorAll('li');
		let last_index = Array.from(buttons).indexOf(last_active);
		let scroll_index = null;

		if (direction && last_index > 0) {
			scroll_index = last_index - 1;
		} else if (!direction && last_index < buttons.length - 1) {
			scroll_index = last_index + 1;
		}

		if (scroll_index !== null)
			switchPage(pagination, table, scroll_index);
	}

	function switchPage(pagination, table, index, bypass = -1)
	{
		let limit = parseInt(table.getAttribute("data-limit"));
		let rows = table.querySelectorAll('.table-row:not(.table-heading)');
		let buttons = pagination.querySelectorAll('li');
		let last_active = pagination.querySelector('li.active');
		let x_pos = parseInt(pagination.getAttribute('data-x'));
		let x_shift = 0;
		let target_pos = (-index + 2) * BTN_WIDTH;
		let page_count = Math.ceil(rows.length / limit);

		if (bypass !== -1) {
			x_shift = (-bypass + 2) * BTN_WIDTH;
		} else {
			if (index > 1 && index < buttons.length - 2) {
				x_shift = target_pos;
			} else if (index === 1) {
				x_shift = 0;
			} else if (index === page_count - 2) {
				x_shift = (-page_count + 5) * BTN_WIDTH;
			} else {
				x_shift = x_pos;
			}
		}

		rows.forEach((row, row_index) => {
			if (row_index < index * limit || row_index >= (index * limit) + limit) {
				row.style.display = 'none';
			} else {
				row.style.display = 'flex';
				row.style.opacity = '0';

				setTimeout(() => {
					row.style.opacity = '1';
				}, 50);
			}
		});

		last_active.classList.remove('active');
		buttons[index].classList.add('active');
		pagination.style.transform = 'translateX(' + x_shift + 'rem)';
		pagination.setAttribute('data-x', x_shift);

		updatePaginationInfos(pagination, table, page_count, index);
		updatePaginationProgress(pagination, index, page_count - 1);
	}

	function updatePaginationInfos(pagination, table, page_count, index)
	{
		let info = pagination.closest('.pagination-container').querySelector('.pagination-info');

		if (info === null || info === undefined)
			return;

		let from = 0, to = 0;
		let rows = table.querySelectorAll('.table-row:not(.table-heading)');
		let started = false;

		for (let i = 1; i < rows.length; i++) {
			let display = rows[i - 1].style.display;

			if (display !== 'none' && !started) {
				started = true;
				from = i;
			} else if ((display === 'none' && started) || i == rows.length - 1) {
				to = i == rows.length - 1 ? rows.length : i - 1;
				break;
			}
		}

		info.innerHTML = 'Displaying ' + from + '-' + to + ' on page ' + (index + 1) + '/' + page_count;
	}

	function initPaginationExtremes(pagination, table, max)
	{
		let container = pagination.closest('.pagination-container');
		let left = container.querySelector('.pagination-left');
		let right = container.querySelector('.pagination-right');

		if (left !== null && left !== undefined) {
			left.addEventListener('click', () => {
				switchPage(pagination, table, 0, Math.min(2, max - 1));
			});
		}

		if (right !== null && right !== undefined) {
			right.addEventListener('click', () => {
				switchPage(pagination, table, max - 1, Math.max(0, max - 3));
			});
		}

		initPaginationSteppedExtremes(pagination, table, container, max);
	}

	function initPaginationSteppedExtremes(pagination, table, container, max)
	{
		let left = container.querySelector('.pagination-left-one');
		let right = container.querySelector('.pagination-right-one');

		if (left !== null && left !== undefined) {
			left.addEventListener('click', () => {
				let last_active = pagination.querySelector('li.active');
				let buttons = pagination.querySelectorAll('li');
				let last_index = Array.from(buttons).indexOf(last_active);

				if (last_index > 0)
					switchPage(pagination, table, last_index - 1);
			});
		}

		if (right !== null && right !== undefined) {
			right.addEventListener('click', () => {
				let last_active = pagination.querySelector('li.active');
				let buttons = pagination.querySelectorAll('li');
				let last_index = Array.from(buttons).indexOf(last_active);

				if (last_index < max - 1)
					switchPage(pagination, table, last_index + 1);
			});
		}
	}

	function updatePaginationProgress(pagination, index, total)
	{
		let dot = pagination.closest('.table-container').querySelector('.progress-point');

		dot.style.left = ((index / total) * 100) + '%';
	}

	function initAutoLimits()
	{
		let table_containers = document.querySelectorAll('.table-container');
		let limit = window.innerHeight / 70;

		table_containers.forEach((container) => {
			let table = container.querySelector('.table');

			container.setAttribute('style', '--data-limit: ' + limit);
			table.setAttribute('data-limit', limit);
		});
	}
</script>
</body>
</html>